<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>简单的选项菜单拖拽</title>
    <style>
        .listBlock{
            width:30%;
            float:left;
            overflow: hidden;
            color:#494949;
            margin-right:3%;
        }
        .ul{
            margin:0;
            list-style: none;
            padding:0;
            border:1px solid #cecece;
            border-radius: 6px;
            width:100%;
            float:left;
            overflow: auto;
            height:300px;
            box-sizing: border-box;
            background:#f3f3f3;
        }
        .ul li{
            line-height:35px;
            padding:0 0 0 10px;
            cursor: pointer;
            border-bottom:1px dotted #cecece;
        }
        .ul li:last-child{
            border:none;
        }
        .delete{
            float:right;
            margin-right:5px;
            font-size:12px;
            color:rgb(122, 122, 122);
        }
    </style>
</head>
<body>

    <div id="content">
        <div class="listContent">
            <div class="listBlock">
                <h3>菜单列表：</h3>
                <ul class="ul">
                    <li v-for="(v,index) in list" 
                    :draggable="draggable" 
                    @dragstart.stop="dragstart($event, v, index, true)"
                    @dragend.stop="dragend($event)"
                    @drag.stop="drag($event)">{{v.optionName}}</li>
                </ul>
            </div>
            <div class="listBlock">
                <h3>已选择列表：</h3>
                <ul class="ul"@dragover.prevent.stop="dragover($event)"
                @drop.stop="drop($event)">
                    <li v-for="(v,index) in selectList" 
                    :draggable="draggable" 
                    @dragstart.stop="dragstart($event, v, index)"
                    @dragend.stop="dragend($event)"
                    @dragover.prevent.stop="dragover($event)"
                    @drop.stop="drop($event, v, index)"
                    >
                        <span class="delete" @click.stop="deleteOption(v, index)">删除</span>
                        {{index + 1}}）{{v.optionName}}
                    </li>
                </ul>
            </div>
        </div>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        var listVue = new Vue({
            el:"#content",
            data:{
                draggable:true, //是否可拖动
                list:[],    //数据列表
                selectList:[],  //已选择数据列表
                menuFlag:false,   //是否是菜单列表
            },
            mounted(){
                this.init();
            },
            methods:{
                //初始化数据
                init(){
                    let arr = [];
                    for(let a=0;a<20;a++){
                        arr.push({
                            id:(a+1),
                            optionName:'列表项'+(a+1)
                        });
                    }
                    this.list = arr;
                },
                //选择列表项
                selectOption(v){
                    this.selectList.push(v);
                },
                //拖动开始时
                dragstart(ev, v, index, flag){
                    //兼容IE
                    var ev = ev || window.event;

                    //兼容火狐
                    if (navigator.userAgent.indexOf('Firefox') >= 0) {
                        ev.dataTransfer = ev.originalEvent.dataTransfer;
                        //设置要写入的信息
                        dt.setData("option", JSON.stringify(v));
                    }
                    //获取拖放时要写入的信息
                    let dt = ev.dataTransfer;

                    //设定effectAllowed属性形式为 copy 复制
                    dt.effectAllowed = 'copy';

                    //设置要写入的信息
                    dt.setData("option", JSON.stringify(v));
                    dt.setData("index", index);

                    if(flag){
                        this.menuFlag = true;
                    }else{
                        this.menuFlag = false;
                    }
                },
                //拖动结束时
                dragend(ev){

                },
                //拖动进行中
                drag(ev){

                },
                //拖动到目标区域时
                dragover(ev){
                    //兼容IE
                    var ev = ev || window.event;
                },
                //拖动完成时
                drop(ev, v, index){

                    //兼容IE
                    var ev = ev || window.event;

                    //兼容火狐
                    if (navigator.userAgent.indexOf('Firefox') >= 0) {
                        ev.dataTransfer = ev.originalEvent.dataTransfer;
                        //设置要写入的信息
                        dt.setData("option", JSON.stringify(v));
                    }
                    //获取拖放时要写入的信息
                    let dt = ev.dataTransfer;
                    
                    let opt = JSON.parse(dt.getData("option"));
                    let old_index = JSON.parse(dt.getData("index"));
                    
                    //可选列表为空
                    if(this.selectList.length<1 || ev.target.nodeName == "UL"){
                        //删拖动元素
                        if(this.menuFlag){
                            this.list.splice(old_index, 1);
                        }else{
                            this.selectList.splice(old_index, 1);
                        }
                        this.selectList.push(opt);
                    }else{
                        if(ev.target.nodeName == "LI"){
                            //向元素下边拖拽
                            if(old_index < index){
                                //console.log("下");

                                //当索引为最后一个元素
                                if(index >= this.selectList.length){
                                    this.selectList.push(opt);
                                }else{
                                    //插入到下一个元素
                                    this.selectList.splice(index + 1, 0, opt);
                                    //删拖动元素
                                    if(this.menuFlag){
                                        this.list.splice(old_index, 1);
                                    }else{
                                        this.selectList.splice(old_index, 1);
                                    }
                                }
                            }else{  //向元素上边拖拽
                                //console.log("上");

                                //删拖动元素
                                if(this.menuFlag){
                                    this.list.splice(old_index, 1);
                                }else{
                                    this.selectList.splice(old_index, 1);
                                }
                                //插入到上一个元素
                                this.selectList.splice(index == 0?0:index, 0, opt);
                            }
                        }
                    }

                },
                //删除元素
                deleteOption(v, index){
                    this.selectList.splice(index, 1);
                    this.list.push(v);
                    this.list.sort((a, b)=>{
                        return a.id - b.id;
                    });
                }
            }
        });
    </script>
</body>
</html>